#pragma once
#include "sock.hpp"
#include "log.hpp"
#include <functional>
#include <poll.h>

uint16_t default_port = 8080;
static const int default_fd = -1; // 默认文件描述符
static const int num = 2048;
using func_t = function<string(const string &)>;

class pollServer
{
public:
    pollServer(func_t func, uint16_t port = default_port)
        : _listensock(-1), _port(port), _rfds(nullptr), _func(func)
    {
    }
    void Print()
    {
        for (int i = 0; i < num; ++i)
        {
            if (_rfds[i].fd != default_fd)
            {
                cout << _rfds[i].fd << " ";
            }
        }
        cout << endl;
    }
    // 这里listensock触发的情况
    void Accepter()
    {
        logMessage(NORMAL, "Accepter in");
        // 这里select一定已经帮我们完成的等待的工作，所以直接获取新连接会使效率大大提高
        string clientip;
        uint16_t clientport;
        int sock = sock::Accept(_listensock, &clientip, &clientport);
        if (sock < 0)
            return;
        logMessage(NORMAL, "accept success: [%s:%d]", clientip.c_str(), clientport);
        // 把新的sock放入到fdarray中，让其帮我们进行等待工作
        int i = 0;
        for (; i < num; ++i)
        {
            if (_rfds[i].fd == default_fd)
                break;
        }
        // 这里有可能已经超过了最大的范围
        if (i == num)
        {
            logMessage(WARNING, "server is full,please wait");
            close(sock);
        }
        else
        {
            // 加入结构体数组中
            _rfds[i].fd = sock;
            _rfds[i].events = POLLIN;
            _rfds[i].revents = 0;
        }
        // 打印出数组中的有效的fd
        Print();
        logMessage(NORMAL, "Accepter out");
    }
    void Recver(int pos)
    {
        logMessage(NORMAL, "Recver in");
        // 这里select已经帮我们完成等待工作，下面直接读取即可，然后处理返回
        // 1.接受request
        char buffer[1024];
        ssize_t s = recv(_rfds[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            buffer[s] = 0;
            logMessage(NORMAL, "client say:%s", buffer);
        }
        else if (s == 0)
        {
            // 读完，关闭fd，同时置空当前数组的fd
            close(_rfds[pos].fd);
            resetitem(pos);
            logMessage(NORMAL, "client quit");
            return;
        }
        else
        {
            // 读取错误，关闭fd，并置空fd
            close(_rfds[pos].fd);
            resetitem(pos);
            logMessage(ERROR, "client quit %s", strerror(errno));
            return;
        }
        // 通过回调函数，处理业务逻辑，这里只是简单的测试
        // 2.处理request
        string response = _func(buffer);
        // 3.返回response，这里本来应该增加一个对write端写的select控制，但是这样太复杂了，只验证读即可
        write(_rfds[pos].fd, response.c_str(), response.size());
        logMessage(NORMAL, "Recver out");
    }
    void handlerEvent()
    {
        // 因为我们是需要遍历所有的fd的，我们并不知道哪个fd已经就绪，所以这里要全部遍历一次
        for (int i = 0; i < num; ++i)
        {
            // 首先先排除一些无效的fd
            if (_rfds[i].fd == default_fd)
                continue;
            if (!(_rfds[i].events & POLLIN))
                continue;
            // 这里是listensock的情况
            if (_listensock == _rfds[i].fd && (_rfds[i].revents & POLLIN))
            {
                Accepter();
            }
            else if (_rfds[i].revents & POLLIN)
            {
                // 其他的读情况条件满足
                Recver(i);
            }
        }
    }
    void resetitem(int i)
    {
        _rfds[i].fd = default_fd;
        _rfds[i].events = 0;
        _rfds[i].revents = 0;
    }
    void initServer()
    {
        // 创建套接字
        _listensock = sock::Socket();
        // 绑定
        sock::Bind(_listensock, _port);
        // 监听
        sock::Listen(_listensock);
        // 对_rfds的初始化
        _rfds = new struct pollfd[num];
        for (int i = 0; i < num; ++i)
        {
            resetitem(i);
        }
        // 这里因为已经创建好监听套接字，直接放入数组中即可
        _rfds[0].fd = _listensock;
        //这里必须设置，不然内核不知道用户想要等待什么
        _rfds[0].events = POLLIN;
    }
    void start()
    {
        int timeout = -1; // 使用阻塞式等待
        for (;;)
        {
            int n = poll(_rfds, num, timeout);
            switch (n)
            {
            case 0:
            {
                // 这里说明是等待时间到了
                logMessage(NORMAL, "timeout ...");
                break;
            }
            case -1:
            {
                // 这里是出错了,打印错误码
                logMessage(WARNING, "select error code:%d,err string:%s", errno, strerror(errno));
                break;
            }
            default:
            {
                // 这里说明已经有至少一个链接就绪了，我们可以进行读取了
                logMessage(NORMAL, "have a event ready!");
                handlerEvent();
                break;
            }
            }
        }
    }
    ~pollServer()
    {
        if (_listensock > 0)
        {
            close(_listensock);
        }
        if (_rfds)
            delete[] _rfds;
    }

private:
    int _listensock;      // 监听套接字
    uint16_t _port;       // 端口号
    struct pollfd *_rfds; // 相当于poll的数组
    func_t _func;
};
